package com.xenstra.bhavcopydownloader;

import static com.xenstra.bhavcopydownloader.Utils.getDoubleDigitString;

import java.io.File;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Downloader {

	private static final String EQUITY_DOWNLOAD_BASE_URL = "http://www.nseindia.com/content/historical/EQUITIES/";
	private static final String DERIVATIVES_DOWNLOAD_BASE_URL = "http://www.nseindia.com/content/historical/DERIVATIVES/";
	
	private String baseDownloadFolder;
	private Calendar startDate, endDate;
	
	
	private static String[] monthNames;

	static{
		monthNames = DateFormatSymbols.getInstance().getShortMonths();
		for(int i=0;i<monthNames.length;i++){
			monthNames[i] = monthNames[i].toUpperCase();
		}
	}
	
	
	public Downloader(String baseDownloadFolder, Calendar startDate) {
		super();
		this.baseDownloadFolder = baseDownloadFolder;
		this.startDate = startDate;
	}

	public Downloader(String baseDownloadFolder, Calendar startDate,
			Calendar endDate) {
		super();
		this.baseDownloadFolder = baseDownloadFolder;
		this.startDate = startDate;
		this.endDate = endDate;	
	}
	
	public void downloadSingleDayFiles(){
		DownloadInfo downloadLinks = createDownloadLinks(baseDownloadFolder, startDate);
		if(downloadLinks != null){
			createDownloadFolderIfNeeded(downloadLinks.getDownloadFolder());
			// since there is only a single date to download for, no need to build a multi-threaded system.
			// just download the files one after another.
			try {
				new Worker(downloadLinks.getDownloadFolder(), downloadLinks.getEquityDownloadUrl()).call();	// Equity
				new Worker(downloadLinks.getDownloadFolder(), downloadLinks.getDerivativeDownloadUrl()).call();	// Derivative
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void startDownloads(){
		long startTime = System.currentTimeMillis();
		List<Callable<Boolean>> tasks = new LinkedList<Callable<Boolean>>();
		
		while(!startDate.after(endDate)){
			DownloadInfo downloadLinks = createDownloadLinks(baseDownloadFolder, startDate);
			
			if(downloadLinks != null){
				// Create the directory if not already present. 
				// Not created through the workers because of their multithreaded mode of execution.
				createDownloadFolderIfNeeded(downloadLinks.getDownloadFolder());
				
				tasks.add(new Worker(downloadLinks.getDownloadFolder(), downloadLinks.getEquityDownloadUrl()));	// Equity
				tasks.add(new Worker(downloadLinks.getDownloadFolder(), downloadLinks.getDerivativeDownloadUrl()));	// Derivative
			}
			startDate.add(Calendar.DATE, 1);
		}
		System.out.println("Submitting " + tasks.size() + " download tasks....");
		ExecutorService executor = Executors.newFixedThreadPool(15);
		try {
			executor.invokeAll(tasks);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		executor.shutdown();
		System.out.println("\n\ntime taken :" + (System.currentTimeMillis() - startTime)/1000 + " secs");
	}

	private void createDownloadFolderIfNeeded(String downloadFolder) {
		File dir = new File(downloadFolder);
		dir.mkdirs();
	}
	
	private DownloadInfo createDownloadLinks(String baseDownloadFolder, Calendar date){
		if(date.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || date.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
			System.out.printf("%1$tc is SATURDAY or SUNDAY\n", date);
			return null;
		}
		
		int day = date.get(Calendar.DATE);
		int month = date.get(Calendar.MONTH);
		int year = date.get(Calendar.YEAR);
		String dayString = getDoubleDigitString(day), monthString =  monthNames[month];
				
		DownloadInfo downloadLinks = new DownloadInfo(
				baseDownloadFolder + File.separator + year + File.separator + getDoubleDigitString(month + 1),
				EQUITY_DOWNLOAD_BASE_URL + year + "/" + monthString + "/cm" + dayString + monthString + year + "bhav.csv.zip",
				DERIVATIVES_DOWNLOAD_BASE_URL + year + "/" + monthString + "/fo" + dayString + monthString + year + "bhav.csv.zip"
			);

		return downloadLinks;
	}
	
	private class DownloadInfo{
		
		private String downloadFolder;
		private String equityDownloadUrl;
		private String derivativeDownloadUrl;
		
		public DownloadInfo(String downloadFolder, String equityDownloadUrl,
				String derivativeDownloadUrl) {
			super();
			this.downloadFolder = downloadFolder;
			this.equityDownloadUrl = equityDownloadUrl;
			this.derivativeDownloadUrl = derivativeDownloadUrl;
		}

		public String getDownloadFolder() {
			return downloadFolder;
		}

		public String getEquityDownloadUrl() {
			return equityDownloadUrl;
		}

		public String getDerivativeDownloadUrl() {
			return derivativeDownloadUrl;
		}

	}
}
